#include "../common.h"

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;      // 每个任务的唯一标识符
    uint32_t _timeout; // 超时时间
    bool _cancel = false; // 不能从wheel去取消,wheel中取消只是提前释放,会导致任务提前执行
    TaskFunc _task_cb;    // 执行的具体任务
    ReleaseFunc _release; // 释放函数

public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc& cb)
    :_id(id),
    _timeout(delay),
    _task_cb(cb)
    {}
    
    uint32_t Gettimeout()
    {return _timeout;}

    // 设置释放函数,让外部传一个释放函数进来,让TimerTask知道释放函数要做什么
    void SetRealease(const ReleaseFunc& cb)
    {_release = cb;}

    void CancelTask()
    {_cancel = true;}

    ~TimerTask()
    {
        // 当任务没有被取消时,执行任务
        if(_cancel == false)_task_cb();
        _release();
    }
};




// 任务的释放思路: 如果任务有了IO操作，就用新的share_ptr对该任务进行拷贝，使其计数器加1，这样旧的share_ptr被释放后仅仅是对计数器-1
//                如果任务没有操作，到点了就该被释放，此时计数器为0，就会自动走析构函数
class TimerWheel
{
private:
    using PtrTask = std::shared_ptr<TimerTask>;

    int _tick;          // 秒针
    int _capacity;      // 最大容量
    std::vector<std::vector<PtrTask>> _wheel; // 使用智能指针去存储任务,任务结束时会对计数器减1
    
    std::unordered_map<uint64_t, std::weak_ptr<TimerTask>> _timer; // 对每个任务的保存,使用weak_ptr保存,便于后面任务刷新时用新的share_ptr去拷贝

public:
    TimerWheel(int tick = 0, int capacity = 60)
    :_tick(tick),
    _capacity(capacity),
    _wheel(_capacity)
    {}

    // 设置TimerTask的释放函数
    void RemoveTimer(uint64_t id)
    {
        // 将unordered_map中id和对应的weak_ptr删除即可
        auto ret = _timer.find(id);
        if(ret != _timer.end())
        {
            _timer.erase(id); // 找到了就删掉
        }
    }

    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc& cb)
    {
        std::shared_ptr<TimerTask> pt(new TimerTask(id, delay, cb)); // 创建实例化任务对象的智能指针
        pt->SetRealease(std::bind(&TimerWheel::RemoveTimer, this, id));
        int pos = (delay + _tick) % _capacity;
        _wheel[pos].push_back(pt);
        _timer[id] = pt;
    }
    // 刷新定时任务 只需要知道id就可以进行刷新
    void TimerRefresh(uint64_t id)
    {
        auto ret = _timer.find(id);
        if(ret == _timer.end())
        {
            return; // 没有在map中找到保存的任务,直接退出
        }
        //std::shared_ptr<TimerTask> pt = _timer[id].lock(); // weak的lock函数是返回它指向对象的share_ptr指针
        auto pt = ret->second.lock();
        int pos = (_tick + pt->Gettimeout()) % _capacity; /*std::cout << "pos = " << pos << std::endl;*/
        _wheel[pos].push_back(pt);
    } 

    // tick往后走并执行(释放)数组对应位置的所有任务
    void RuntimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        // std::cout << "_tick: " << _tick << std::endl;
        _wheel[_tick].clear();        // 将该位置的数组全部释放(只要释放,智能指针就会调用析构函数)
    }

    void SetCancel(uint64_t id)
    {
        auto ret = _timer.find(id);
        if(ret == _timer.end())
        {
            return; // 没有在map中找到保存的任务,直接退出
        }
        std::shared_ptr<TimerTask> pt = ret->second.lock();
        pt->CancelTask();
    }
};

class Test
{
public:
    Test()
    {
        std::cout << "构造\n";
    }
    ~Test()
    {
        std::cout << "析构\n";
    }
};

void Delete(Test* t)
{
    delete t;
}

int main()
{
    TimerWheel tw;
    Test* t = new Test();

    tw.TimerAdd(999, 5, std::bind(&Delete, t));

    for(int i = 3; i > 0; i--)
    {
        sleep(1);
        tw.TimerRefresh(999);
        tw.RuntimerTask();
        std::cout << "刷新了任务\n";
    }
    while(1)
    {
        sleep(1);
        tw.SetCancel(999);
        std::cout << "-----------------------------\n";
        tw.RuntimerTask();
    }
    return 0;
}